#include "neuron.h"


neuron::neuron(const int syn_count){
  neuron_id    = -1;
  _psynapse    = NULL;
  _pcalcfunc   = NULL;
  setSynapseCount(syn_count);
  setActivTiling(0.5);
  init();
}

neuron::neuron(const neuron& data)
{
  activ_tiling       = data.activ_tiling;
  synapse_count      = data.synapse_count;
  _axon              = data._axon;
  _pcalcfunc         = data._pcalcfunc;
  study_buffer_index = data.study_buffer_index;
  neuron_id          = data.neuron_id;
  init();
  for(int isyncount = 0; isyncount < synapse_count; isyncount++)
  {
    _psynapse[isyncount] = data._psynapse[isyncount];
  }
}

neuron& neuron::operator=(const neuron& data) {
  activ_tiling       = data.activ_tiling;
  synapse_count      = data.synapse_count;
  _axon              = data._axon;
  _pcalcfunc         = data._pcalcfunc;
  study_buffer_index = data.study_buffer_index;
  neuron_id          = data.neuron_id;
  init();
  for(int isyncount = 0; isyncount < synapse_count; isyncount++)
  {
    _psynapse[isyncount] = data._psynapse[isyncount];
  }
  return *this;
}

neuron::neuron(){
  neuron_id  = -1;
  _psynapse  = NULL;
  _pcalcfunc = NULL;
  setSynapseCount(0);
  setActivTiling(0.5);
}

neuron::~neuron(void){
  if(_psynapse != NULL && synapse_count > 0) {
    delete [] _psynapse;
    _psynapse = NULL;
  }
}

void neuron::init() {
  if(_psynapse != NULL && synapse_count > 0) {
    delete [] _psynapse;
	_psynapse = NULL;
  }
  if(synapse_count > 0)
    _psynapse = new synapse[synapse_count];
}

void neuron::setNeuronID(int id) {
   neuron_id = id;
}

int neuron::getNeuronID()
{
  return neuron_id;
}


void neuron::setActivTiling(double v) {
   activ_tiling = v;
}

double neuron::getActivTiling() {
  return activ_tiling;
}

void neuron::setSynapseCount(int v) {
  synapse_count = v;
}

int neuron::getSynapseCount() {
  return synapse_count;
}


void neuron::setCalcFunction(neuron_calc *pf) {
  _pcalcfunc = pf;
}

synapse neuron::getSynapse(int i){
  if(i < synapse_count) {
    return _psynapse[i];
  }
  return synapse();
}

bool neuron::setSynapse(const synapse& syn, int i){
  bool bret_value = false;
  if(i < synapse_count) {
    _psynapse[i] = syn;
    bret_value = true;
  }
  return bret_value;
}

axon neuron::getAxon(void){
  return _axon;
}

void neuron::setAxon(const axon& v){
  _axon = v;
}

double neuron::calc(void){
  int icount = 0;
  double synapse_val = 0.0;
  double calc_value = 0.0;

  for(; icount < synapse_count; icount ++)
   synapse_val += _psynapse[icount].getFSignal() * _psynapse[icount].getWeight();

  synapse_val = synapse_val / (double)synapse_count;
  calc_value = _pcalcfunc->calc(synapse_val, activ_tiling);
  _axon.setFSignal(calc_value);
  return calc_value;
}

double neuron::calc_study(void){
  int icount = 0;
  double synapse_val = 0.0;
  double calc_value = 0.0;

  for(; icount < synapse_count; icount ++)
	  synapse_val += _psynapse[icount].getFSignalStudy(study_buffer_index) * _psynapse[icount].getWeight()/*.getWeightStudy(study_buffer_index)*/;

  synapse_val = synapse_val / (double)synapse_count;
  calc_value = _pcalcfunc->calc(synapse_val, activ_tiling);
  _axon.setFStudySignal(study_buffer_index, calc_value);
  return calc_value;
}

void neuron::calc_back(void){
  double signal = _axon.getBSignal();
  int icount = 0;
  int itmp_count = 0;
  double synapse_val = 0.0;
  double calc_value = 0.0;
  double tmp_val = 0.0;
  double tmp_syn_val = 0.;

  calc_value = _pcalcfunc->calc_back(signal, activ_tiling);
  for(icount  = 0; icount < synapse_count; icount ++){
	tmp_val = 0.0;
    for(itmp_count = 0; itmp_count < synapse_count; itmp_count ++) {
      if(itmp_count == icount)
        continue;
	  tmp_val += (_psynapse[itmp_count].getFSignalStudy(study_buffer_index) * _psynapse[itmp_count].getWeight());
    }
    tmp_syn_val = calc_value - tmp_val;
	tmp_val = tmp_syn_val / _psynapse[icount].getWeight();
	_psynapse[icount].setBSignal(tmp_val);
  }
}

void neuron::calc_back_study(void){
  double signal = _axon.getBStudySignal(study_buffer_index);
  int icount = 0;
  int itmp_count = 0;
  double synapse_val = 0.0;
  double calc_value = 0.0;
  double tmp_val = 0.0;
  double tmp_syn_val = 0.;

  calc_value = _pcalcfunc->calc_back(signal, activ_tiling);
  for(icount  = 0; icount < synapse_count; icount ++){
	tmp_val = 0.0;
    for(itmp_count = 0; itmp_count < synapse_count; itmp_count ++) {
      if(itmp_count == icount)
        continue;
	  tmp_val += (_psynapse[itmp_count].getFSignalStudy(study_buffer_index) * _psynapse[itmp_count]/*.getWeightBack(study_buffer_index)*/.getWeight());
    }
    tmp_val = tmp_val / ((double)(synapse_count - 1));
    tmp_syn_val = calc_value - tmp_val;
	tmp_val = tmp_syn_val / _psynapse[icount]./*getWeightBack(study_buffer_index);*/ getWeight();
	_psynapse[icount].setBSignalStudy(study_buffer_index, tmp_val);
  }
}

void neuron::setStudyBufferIndex(int index)
{
  study_buffer_index = index;
}

double neuron::clac_back_synapse_w(int syn_id)
{
  double signal = _axon.getBStudySignal(study_buffer_index);
  int icount = 0;
  int itmp_count = 0;
  double synapse_val = 0.0;
  double calc_value = 0.0;
  double tmp_val = 0.0;
  double tmp_syn_val = 0.;

  calc_value = _pcalcfunc->calc_back(signal, activ_tiling);
  tmp_val = 0.0;
  for(itmp_count = 0; itmp_count < synapse_count; itmp_count ++) {
    if(itmp_count == icount)
      continue;
    tmp_val += (_psynapse[itmp_count].getFSignalStudy(study_buffer_index) * _psynapse[itmp_count].getWeight());
  }
  tmp_syn_val = (calc_value * (double)synapse_count) - tmp_val;
  tmp_val = tmp_syn_val / _psynapse[icount].getFSignalStudy(study_buffer_index);
  return tmp_val;
}

